<?php
/**
 * Copyright (c) 2020
 * 摘    要：
 * 作    者：san
 * 修改日期：2020.04.06
 */

namespace App\Library\AutoDs;

use App\Library\Traits\Helper;
use App\Model\Project;
use ErrorException;

class Command
{
    use Helper;

    /**
     * @var Project $config
     */
    protected $config;
    protected $status  = 1;
    protected $command = [];
    protected $log     = null;

    /**
     * Command constructor.
     *
     * @param $config
     * @throws ErrorException
     */
    public function __construct($config)
    {
        if ($config) {
            $this->config = $config;
        } else {
            throw new ErrorException(t('message.12063'));
        }
    }

    /**
     * Get executed command
     *
     * @return string
     */
    public function getEXeCommand()
    {
        return array_unique($this->command);
    }

    public function setExeCommand($command)
    {
        $this->command[] = $command;
    }

    /**
     * Get execution log
     *
     * @return string
     */
    public function getExeLog()
    {
        return $this->log;
    }

    public function setExeLog($log)
    {
        $this->log = $this->log . PHP_EOL . $log;
    }

    /**
     * Get execution log
     *
     * @return string
     */
    public function getExeStatus()
    {
        return $this->status;
    }


    /**
     * Get configuration
     */
    protected function getConfig()
    {
        return $this->config;
    }

    /**
     * Get the number of milliseconds
     *
     * @return int
     */
    public static function getMs()
    {
        return intval(microtime(true) * 1000);
    }

    /**
     * Get the IP or alias of the target machine
     *
     * @param $host
     * @return mixed
     */
    protected function getHostName($host)
    {
        $hostName = explode(':', $host);

        return $hostName[0];
    }

    /**
     * Get the ssh port of the target machine
     *
     * @param     $host
     * @param int $default
     * @return int
     */
    protected function getHostPort($host, $default = 22)
    {
        $hostInfo = explode(':', $host);

        return !empty($hostInfo[1]) ? $hostInfo[1] : $default;
    }

    /**
     * Execute local host commands
     *
     * @param $command
     * @return bool|int
     */
    final protected function _runLocalCommand($command)
    {
        $command = trim($command);
        $this->writeLog('---------------------------------');
        $this->writeLog('---- Executing: $ ' . $command);

        $status = 1;
        $log    = [];

        exec($command . ' 2>&1', $log, $status);
        // 执行过的命令
        $this->setExeCommand($command);

        // 执行的状态
        $this->status = !$status;
        // 操作日志
        $log = implode(PHP_EOL, $log);
        $log && $this->setExeLog(trim($log));
        $this->writeLog($log);
        $this->writeLog('---------------------------------');

        return $this->status;
    }

    /**
     * Execute remote target machine commands
     *
     * @param $command
     * @param bool $grayPush Grayscale publishing
     * @return bool
     */
    final protected function runRemoteCommand($command, $grayPush = false)
    {
        $needTTY = '-T';

        $hosts = $grayPush ? $this->getConfig()->gray_hosts : $this->getConfig()->hosts;

        foreach (str2arr($hosts) as $remoteHost) {

            $localCommand = sprintf('ssh %s -p %d -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=false %s@%s %s',
                $needTTY, $this->getHostPort($remoteHost), escapeshellarg($this->getConfig()->release_user),
                escapeshellarg($this->getHostName($remoteHost)), escapeshellarg($command));

            $this->writeLog('Run remote command ' . $command);
            $this->setExeCommand($command);

            $log = $this->log;
            $log && $this->setExeLog($log);
            $this->status = $this->_runLocalCommand($localCommand);

            if (!$this->status) {
                return false;
            }
        }

        return true;
    }

    /**
     * writeLog
     *
     * @param String $message
     */
    private function writeLog(string $message)
    {
        $filename = BASE_PATH . '/runtime/logs/autods-' . date('Ymd') . ".log";

        $record = is_array($message) ? json_encode($message, JSON_UNESCAPED_UNICODE) : $message;

        file_put_contents($filename, $record . PHP_EOL, FILE_APPEND);
    }
}
